package contegor.scire.core.queries;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import contegor.scire.core.Connectable;
import contegor.scire.core.Container;
import contegor.scire.core.InfiniteSingletonList;
import contegor.scire.core.NeedsPrecedent;
import contegor.scire.core.ReturnPoint;
import contegor.scire.core.ReturnPointAdapter;
import contegor.scire.core.ScireException;
import contegor.scire.core.Task;
import contegor.scire.core.TaskId;

/**
 * {@link Query} that allows to chain {@link Query}s. 
 *
 * @version $Revision$
 * @author  Héctor Cirbián Pousa ($Author$)
 */
public class Extensor<C extends Connectable> extends QueryWithDependenciesAndSubsequentsExtensible<C,C,C> {
  private static final long serialVersionUID = 2677299988511457811L;

  protected List<C> results;

  private ReturnPoint<C> dependenciesReturnPoint = new ReturnPointAdapter<C>() {
    public <U extends C> void manage(TaskId taskId, U result) {
      results.add(result);
    }
    public void manage(TaskId taskId, Exception exception) {
      returnPoint.manage(taskId, exception);
    }
  };
  
  public Extensor(Query<C> dependency) {
    super(dependency);
  }

  @Override
  public void process(Container targetContainer) throws ScireException {}

  @Override
  public List<? extends Task<C>> getDependencies() {
    return this.dependencies;
  }

  @Override
  public List<? extends ReturnPoint<? super C>> getDependenciesReturnPoints() {
    if (this.dependencies == null)
      return Collections.emptyList();
    return new InfiniteSingletonList<ReturnPoint<C>>(dependenciesReturnPoint, dependencies.size());
  }

  @Override
  public Extensor<C> withIt(NeedsPrecedent<? super C, C> subsequent) {
    if (this.results == null)
      this.results = new LinkedList<C>(); 
    return (Extensor<C>)super.withIt(subsequent);
  }

  @Override
  public List<? extends Collection<C>> getResultsForSubsequentTasks() {
    if ((this.subsequents == null) || (this.subsequents.size() == 0))
      return Collections.emptyList();
    if (this.results == null)
      this.results = Collections.emptyList();
    return new InfiniteSingletonList<List<C>>(this.results, this.subsequents.size());
  }

  @Override
  public List<? extends ReturnPoint<? super C>> getSubsequentTasksReturnPoints() {
    if ((this.subsequents == null) || (this.subsequents.size() == 0))
      return Collections.emptyList();
    return new InfiniteSingletonList<ReturnPoint<? super C>>(this.returnPoint, this.subsequents.size());
  }
}